package lib

import (
	"GameServer/Common/data"
	"GameServer/Common/utils"
	"GameServer/Game/errors"
	"GameServer/Game/m"
	"GameServer/Game/sp"
	"fmt"
	"sort"

	log "github.com/sirupsen/logrus"
)

func getDoCollect(compa func(bUinx, eUnix int64) bool) (colloectLst []uint64, ok bool) {
	// 获取活动
	actLst, ok := data.Filters("ActActivities", func(val interface{}) bool {
		valT := val.(data.ActActivity)
		actTyp := int64(valT.ActTyp)
		beginTime, _ := utils.LayoutToTime(valT.BeginTime)
		endTime, _ := utils.LayoutToTime(valT.EndTime)
		return actTyp == data.ActivityEnum.CollectProp && compa(beginTime.Unix(), endTime.Unix())
	})
	if !ok {
		return
	}
	// 记录活动id
	mactiv := make(map[uint64]uint64)
	for _, item := range actLst {
		itemT := item.(data.ActActivity)
		activId := itemT.ActivId
		mactiv[activId] = activId
	}
	// 将活动的道具找出来
	collectLst, ok := data.Filters("CollectPropActivitys", func(val interface{}) bool {
		valT := val.(data.CollectPropActivity)
		if _, ok := mactiv[valT.Id]; ok {
			return true
		}
		return false
	})
	if !ok {
		return
	}
	// 获取所有道具
	for _, item := range collectLst {
		itemT := item.(data.CollectPropActivity)
		for _, itemX := range itemT.CollectProp {
			colloectLst = append(colloectLst, itemX)
		}
	}
	return
}

// 获取没有开启收集活动的道具
func GetNoColloctPropActivityGoodTid() (lst []int64) {
	lst = make([]int64, 0)
	nowUnix := utils.TNow().Unix()
	// 获取没有开启的活动的道具
	collectLst, ok := getDoCollect(func(bUinx, eUnix int64) bool {
		return nowUnix < bUinx || eUnix < bUinx
	})
	if !ok {
		return
	}
	// 记录过滤的道具
	mcollect := make(map[uint64]uint64)
	for _, item := range collectLst {
		mcollect[item] = item
	}
	// 获取开启的活动
	collectLst, ok = getDoCollect(func(bUinx, eUnix int64) bool {
		return bUinx <= nowUnix && nowUnix <= eUnix
	})
	if ok {
		// 从过滤的道具中 删除开启的活动道具
		for _, item := range collectLst {
			delete(mcollect, item)
		}
	}

	for _, item := range mcollect {
		lst = append(lst, int64(item))
	}
	return
}

// 获取当前收集道具活动，如果有多个活动存在，只返回一个活动
func GetCurrentColloctPropActivity() (activ data.ActActivity, err error) {
	nowUnix := utils.TNow().Unix()
	tplLst, ok := data.Filters("ActActivities", func(val interface{}) bool {
		valT := val.(data.ActActivity)
		actTyp := int64(valT.ActTyp)
		beginTime, _ := utils.LayoutToTime(valT.BeginTime)
		endTime, _ := utils.LayoutToTime(valT.EndTime)
		return actTyp == data.ActivityEnum.CollectProp && beginTime.Unix() <= nowUnix && nowUnix <= endTime.Unix()
	})

	if !ok || len(tplLst) == 0 {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到激活活动配置,ActActivities,或者没有收集活动")
		return
	}

	activ = tplLst[0].(data.ActActivity)
	return
}

// 获取模板奖励
func GetLevelCollectPropAll(tableId int64) (tplLstT []data.LevelCollectProp, err error) {
	levelTable := fmt.Sprintf("LevelCollectProp%d", tableId)
	// 获取道具等级信息
	tplLst, ok := data.GetAllDatas(levelTable)
	if !ok || len(tplLst) == 0 {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到%s配置表,或者表中没有数据", levelTable))
		return
	}
	tplLstT = make([]data.LevelCollectProp, 0)
	for _, item := range tplLst {
		itemT := item.(data.LevelCollectProp)
		tplLstT = append(tplLstT, itemT)
	}
	sort.Slice(tplLstT, func(i, j int) bool {
		return tplLstT[i].Id < tplLstT[j].Id
	})
	return
}

// 获取用户收集活动信息
func GetColloctProp(us *m.User) (uColloctProp *m.UserColloctProp, err error) {
	uColloctProp = m.GetUserColloctProp(us.Uid.Hex())
	nowUnix := utils.TNow().Unix()
	// 活动正在进行，不用做处理
	if uColloctProp.BeginTime <= nowUnix && nowUnix <= uColloctProp.EndTime {
		return
	}
	// 活动结束，查看是否有活动开启
	activ, err := GetCurrentColloctPropActivity()
	if err != nil {
		log.WithFields(log.Fields{
			"err":    err,
			"uid":    us.Uid.Hex(),
			"method": "GetColloctProp",
		}).Error("没有收集道具活动开启")
		return
	}
	// 获取收集活动的信息
	tpl, ok := data.Get("CollectPropActivitys", activ.ActivId)
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到激活活动配置,CollectPropActivitys,或者没有收集活动 %d", activ.ActivId))
		log.WithFields(log.Fields{
			"err":    err,
			"uid":    us.Uid.Hex(),
			"method": "GetColloctProp",
		}).Error("没有收集道具活动数据")
		return
	}
	tplT := tpl.(data.CollectPropActivity)
	tplLst, err := GetLevelCollectPropAll(int64(tplT.LevelCollectProp))
	if err != nil {
		log.WithFields(log.Fields{
			"err":    err,
			"uid":    us.Uid.Hex(),
			"method": "GetColloctProp",
		}).Error("没有收集道具活动数据")
		return
	}

	bTime, _ := utils.LayoutToTime(activ.BeginTime)
	eTime, _ := utils.LayoutToTime(activ.EndTime)
	// 初始化玩家的数据
	uColloctProp.ActivId = int64(activ.ActivId)
	uColloctProp.BeginTime = bTime.Unix()
	uColloctProp.EndTime = eTime.Unix()
	uColloctProp.Level = 1
	uColloctProp.MaxLevel = int64(len(tplLst))
	uColloctProp.MProp = make(map[int64]int64)
	uColloctProp.State = 0
	uColloctProp.MReachColloctProp = make(map[int64]m.ReachColloctProp)

	for _, item := range tplT.CollectProp {
		itemT := int64(item)
		uColloctProp.MProp[itemT] = 0
	}
	// 记录达成条件的道具
	for _, item := range tplLst {
		mProp := make(map[int64]int64)
		// 填充道具和道具数量
		for idx, itemT := range item.Prop {
			goodId := int64(tplT.CollectProp[idx])
			mProp[goodId] = int64(itemT)
		}
		// 填充奖励
		lReward := make([]m.BaseKV, 0)
		for _, itemT := range item.Reward {
			lReward = append(lReward, m.BaseKV{
				Key: int64(itemT.Key),
				Val: int64(itemT.Value),
			})
		}
		reachProp := m.ReachColloctProp{
			MProp:   mProp,
			LReward: lReward,
		}
		uColloctProp.MReachColloctProp[int64(item.Id)] = reachProp
	}

	uColloctProp.Update(uColloctProp)
	return
}

// 给用户添加收集活动道具
func AddGoodColloctProp(us *m.User, good data.Good, num int64, PSend func(interface{}) error) {
	uColloctProp := m.GetUserColloctProp(us.Uid.Hex())
	activId := utils.Int64(good.Effect)
	// 收集的道具绑定的活动id和玩家身上的活动id不一样，不做处理
	if uColloctProp.ActivId != activId {
		return
	}
	goodId := int64(good.Id)
	// 给该道具添加数量
	uColloctProp.MProp[goodId] += num
	// 判断达成条件
	reachProp, _ := uColloctProp.MReachColloctProp[uColloctProp.Level]
	flag := true // 用户所有道具都大于等于条件，该值为true
	for key, val := range reachProp.MProp {
		if uColloctProp.MProp[key] < val {
			flag = false
			break
		}
	}
	if flag {
		uColloctProp.State = 1
		// 通知客户端有收集任务完成
		PSend(&sp.ColloctPropNoticeRequest{
			ActivId: uColloctProp.ActivId,
		})
	}
	uColloctProp.Update(uColloctProp)
}

// 领取收集道具的奖励
func GetColloctPropReward(from string, us *m.User, activId int64, level int64, PSend func(interface{}) error) (uColloctProp *m.UserColloctProp, uProp *m.UpdateProp, resGoods []*m.Goods, boxResList []*m.BoxRes, err error) {
	uColloctProp = m.GetUserColloctProp(us.Uid.Hex())
	if uColloctProp.State != 1 {
		err = errors.NewErrcode(data.Errcode.ServerErr, fmt.Sprintf("该等级的状态未完成 %d", uColloctProp.State))
		return
	}
	// 圣诞树，该等级状态为1，已完成。
	// 领取该等级的道具
	reachProp, _ := uColloctProp.MReachColloctProp[uColloctProp.Level]

	// 给用户道具
	uProp, resGoods, boxResList, err = GiveGoodsByKvList(from, us, reachProp.LReward, PSend)
	if err != nil {
		log.WithFields(log.Fields{
			"err":    err,
			"uid":    us.Uid.Hex(),
			"method": "GetColloctPropReward",
		}).Error("收集道具给奖励失败")
		return
	}
	// 给道具成功，将该等级的状态修改为0
	uColloctProp.State = 0
	// 领取道具，扣掉捡到的道具
	for key, val := range reachProp.MProp {
		uColloctProp.MProp[key] -= val
	}
	// 提升圣收集道具的等级
	uColloctProp.Level++
	// 当圣诞树等级达到最大级，循环最后一个等级。
	if uColloctProp.Level > uColloctProp.MaxLevel {
		uColloctProp.Level = uColloctProp.MaxLevel
	}
	// 扣掉道具，任然可以领取奖励，将状态改为1，可领取。
	reachProp, _ = uColloctProp.MReachColloctProp[uColloctProp.Level]
	flag := true // 用户所有道具都大于等于条件，该值为true
	for key, val := range reachProp.MProp {
		if uColloctProp.MProp[key] < val {
			flag = false
			break
		}
	}
	// 该等级的圣诞树道具达到要求，将状态改为完成
	if flag {
		uColloctProp.State = 1
	}
	uColloctProp.Update(uColloctProp)
	return
}

// 重置收集数据
func ResetCollectProp(us *m.User) {
	uColloctProp := m.GetUserColloctProp(us.Uid.Hex())
	uColloctProp.Level = 1
	uColloctProp.State = 0
	lst := make([]int64, 0)
	for key := range uColloctProp.MProp {
		lst = append(lst, key)
	}
	for _, item := range lst {
		uColloctProp.MProp[item] = 0
	}
	uColloctProp.Update(uColloctProp)
}

// 给指定道具加数量
func AddCollectProp(us *m.User, goodTid int64, goodNum int64, PSend func(interface{}) error) {
	tpl, ok := data.Get("Goods", uint64(goodTid))
	if !ok {
		return
	}
	tplT := tpl.(data.Good)
	AddGoodColloctProp(us, tplT, goodNum, PSend)
}
